package com.lanhai.longheng.impl;

import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.lanhai.longheng.MsgCore;
import com.lanhai.longheng.beans.AgvBean;
import com.lanhai.longheng.beans.AgvMountBean;
import com.lanhai.longheng.beans.DeviceBean;
import com.lanhai.longheng.beans.DeviceMountBean;
import com.lanhai.longheng.beans.DotBean;
import com.lanhai.longheng.dao.DeviceGroupDao;
import com.lanhai.longheng.dao.RoadDeviceDao;
import com.lanhai.longheng.dao.TransLogDao;
import com.lanhai.longheng.dispatch.AgvCmdMap;
import com.lanhai.longheng.dispatch.DeviceCmdMap;
import com.lanhai.longheng.enums.AgvCurrentTransEnum;
import com.lanhai.longheng.enums.TransDirectionEnum;
import com.lanhai.longheng.interfaces.IAgv;
import com.lanhai.longheng.interfaces.IAgvEvent;
import com.lanhai.longheng.interfaces.IAgvMount;
import com.lanhai.longheng.interfaces.IDevice;
import com.lanhai.longheng.interfaces.IDeviceMount;
import com.lanhai.longheng.interfaces.IDeviceProtocol;
import com.lanhai.longheng.interfaces.IDot;
import com.lanhai.longheng.interfaces.IDotEvent;
import com.lanhai.longheng.interfaces.ISendData;
import com.lanhai.longheng.mapper.RoadMapper;
import com.lanhai.longheng.mapper.TransLogMapper;
import com.lanhai.longheng.third.DeviceFactory;
import com.lanhai.longheng.utils.Tools;

/**
 * 小车的装货情况 agvmount_{agvid}
 * 
 * @author zhengwei
 *
 */
@Service
public class AgvMountImpl implements IAgvMount {

	@Autowired
	IDevice iDevice;

	@Autowired
	IDeviceMount iDeviceMount;

	@Autowired
	IAgv iAgv;

	@Autowired
	IDot iDot;

	@Autowired
	ISendData sendTools;

	@Autowired
	IAgvEvent iAgvEvent;

	@Autowired
	IDotEvent iDotEvent;

	@Autowired
	RoadMapper roadMapper;

	@Autowired
	TransLogMapper tLogMapper;

	static Map<Integer, Long> logMap = Collections.synchronizedMap(new HashMap<Integer, Long>());
	private static final Logger agvlog = LogManager.getLogger("agvlog");

	/**
	 * 双方装货情况的判断
	 */
	@Override
	public void judgement(AgvBean agv, DeviceBean device, DotBean dot, AgvMountBean agvMount) {
		// 装料情况和工序上的判断
		if (Tools.agvCanTrans(device.getProcess(), agvMount) == false) {
			MsgCore.sendMsg(agv.getAgvId(), "所在点位工序不对，不能发起传输");
			return;
		}

		IDeviceProtocol deviceEvent = DeviceFactory.getDevice(device.getCmdSign());
		if (deviceEvent == null) {
			// 机台没有对应的解析
			agvlog.debug("机台没有对应的解析类");
			MsgCore.sendMsg(agv.getAgvId(), "机台没有对应的解析类");
			return;
		}

		// 处理传输完成,满足离开条件就离开
		if (DeviceCmdMap.canLeave(device.getDeviceid())) {
			agvLeave(dot, agv, device, deviceEvent);
			return;
		}

		// 处理转动皮带
		if (DeviceCmdMap.canReceive(device.getDeviceid())) {
			// 传输过程中，直接过滤
			if (AgvCmdMap.isTransing(agv.getAgvId()) == false) {
				// 如果不在传输中，就启动
				MsgCore.sendMsg(agv.getAgvId(), "皮带开始转动");
				AgvCmdMap.setTransing(agv.getAgvId(), true);
				switch (agv.getCurrentTrans()) {
				case DownIn:
					iAgvEvent.transDown(agv, true);
					break;
				case DownOut:
					iAgvEvent.transDown(agv, false);
					break;
				case UpIn:
					iAgvEvent.transUp(agv, true);
					break;
				case UpOut:
					iAgvEvent.transUp(agv, false);
					break;
				case UpInAndDownOut:
					iAgvEvent.transUpInAndDownOut(agv);
					break;
				case UpOutAndDownIn:
					iAgvEvent.transUpOutAndDownIn(agv);
					break;
				default:
					MsgCore.sendMsg(agv.getAgvId(), "未知的传输模式");
					break;
				}
			}
			return;
		}

		// 机台允许传输，申请皮带转动
		if (DeviceCmdMap.canTrans(device.getDeviceid())) {
			MsgCore.sendMsg(agv.getAgvId(), "申请传输");
			byte[] cmd = deviceEvent.applyRecieve(device.getLine(), device.getFillType());
			sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请AGV皮带转动", cmd,
					device.getDeviceGroup());
			return;
		}

		//// 后面的是AGV到机台位置，告之机台AGV已就位的消息

		// 拿到对接设备的解析方式
		DeviceMountBean dmount = iDeviceMount.getBean(device.getDeviceid());
		if (dmount == null) {
			// 设备装卸信息不存在
			agvlog.debug("设备装卸信息不存在");
			MsgCore.sendMsg(agv.getAgvId(), "机台装卸信息不存在");

			return;
		}
		if (dmount.isAllowIn() == false && dmount.isAllowOut() == false) {
			// 机台物料信息不足
			MsgCore.sendMsg(agv.getAgvId(),
					String.format("花篮数量不满足传输,进料：%d，出料：%d ", 10 - dmount.getInNum(), dmount.getOutNum()));
			return;
		}

		// 只上料部分
		if (device.getFillType() == TransDirectionEnum.OnlyIn) {
			if (dmount.isAllowIn()) {
				agvlog.debug(String.format("AGV【%d】处理上料", agv.getAgvId()));
				onlyIn(agv, agvMount, dot, device, deviceEvent);
			} else {
				MsgCore.sendMsg(agv.getAgvId(), String.format("等待花篮数量,进料：%d ", 10 - dmount.getInNum()));

			}

			return;
		}

		// 只出料
		if (device.getFillType() == TransDirectionEnum.OnlyOut) {
			if (dmount.isAllowOut()) {
				agvlog.debug(String.format("AGV【%d】处理下料", agv.getAgvId()));
				onlyOut(agv, agvMount, dot, device, deviceEvent);
			} else {
				MsgCore.sendMsg(agv.getAgvId(), String.format("等待花篮数量,出料：%d ", dmount.getOutNum()));

			}
			return;
		}

		// 同时上下料
		if (device.getFillType() == TransDirectionEnum.Both) {
			if (dmount.isAllowIn() && dmount.isAllowOut()) {
				agvlog.debug(String.format("AGV【%d】同时上下料", agv.getAgvId()));
				InAndOut(agv, agvMount, dot, device, deviceEvent);
			} else {
				MsgCore.sendMsg(agv.getAgvId(),
						String.format("等待花篮数量,进料：%d，出料：%d ", 10 - dmount.getInNum(), dmount.getOutNum()));

			}
			return;
		}
	}

	void agvLeave(DotBean dot, AgvBean agv, DeviceBean device, IDeviceProtocol deviceEvent) {
		// 找目标机台，找到后退回
		if (dot.getRouteRoad() > 0) {
			agv.setNextRoad(dot.getRouteRoad());
			agv.setNextProcess(dot.getNextProcess());
			agv.setNextNode("行驶路线：" + dot.getRouteRoad());
		} else {
			// 其次设备优先、工序优先
			if (agv.getNextRoad() > 0) {
				agvlog.info(String.format("小车[%d]已经有路线[%d]了，不需要做查找", agv.getAgvId(), agv.getNextRoad()));
			} else {
				// 找机台并锁机台，确定路线
				if (findRoad(agv, dot.getDotNO(), dot.getNextProcess(), agv.getSpecialline()) == false) {
					return;
				}
			}
		}
		agv.setFinishTrans(true);
		iAgv.saveCache(agv);

		// 释放机台装料情况（不是解锁机台）
		iDeviceMount.clear(device.getDeviceid());

		// 让小车完成传输，退回二维码处
		iAgvEvent.stopTrans(agv);

		MsgCore.sendMsg(agv.getAgvId(), agv.getNextNode());

		Long latTime = logMap.get(agv.getAgvId());
		long ctime = System.currentTimeMillis();
		if (latTime == null || ctime - latTime > 10000) {
			// 距离上一次入库有10秒以上，可以入库
			logMap.put(agv.getAgvId(), ctime);
			TransLogDao lg = new TransLogDao();
			Calendar c = Calendar.getInstance(Locale.CHINA);
			lg.setAgvid(agv.getAgvId());
			lg.setDotno(dot.getDotNO());
			lg.setDays(c.get(Calendar.YEAR) * 10000 + (c.get(Calendar.MONTH) + 1) * 100 + c.get(Calendar.DAY_OF_MONTH));
			lg.setHours(c.get(Calendar.HOUR_OF_DAY) * 100 + c.get(Calendar.MINUTE));
			lg.setSpecialline(agv.getSpecialline());
			tLogMapper.addLog(lg);
		}

		// 向机台发送离开的信号
		byte[] cmd = deviceEvent.agvLeave(device.getLine());
		sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "AGV离开", cmd,
				device.getDeviceGroup());

	}

	/**
	 * 只是找目标机台，AGV不做移动操作
	 * 
	 * @param agv
	 * @param dotno
	 * @param nextProcess
	 * @param specialline
	 * @param transType
	 * @return
	 */
	boolean findRoad(AgvBean agv, int dotno, String nextProcess, int specialline) {

		DeviceGroupDao gbean = iDevice.findNextDevice(agv.getAgvId(), nextProcess, specialline);
		if (gbean == null) {
			// road=暂时不可用
			agvlog.info(String.format("%s没有可用的机台，等待中", nextProcess));
			MsgCore.sendMsg(agv.getAgvId(), String.format("%s没有可用的机台，等待中", Tools.getProcess(nextProcess)));

			return false;
		} else {
			// 给路线
			RoadDeviceDao roadDao = roadMapper.getTransRoadFromDevice(dotno, gbean.getDotno());
			if (roadDao != null && roadDao.getRoad() > 0) {
				// >0 有效
				iDevice.lockDevice(gbean.getDeviceid(), agv.getAgvId());
				// 注意，此处不解锁本机台，此时此刻agv需要锁两个机台的

				// 保存小车状态
				agv.setFinishTrans(true);
				agv.setNextDeviceid(gbean.getDeviceid());
				agv.setNextRoad(roadDao.getRoad());
				agv.setNextNode(String.format("%s", roadDao.getDevicegroup()));
				// 更新目标工序
				agv.setNextProcess(nextProcess);

				MsgCore.sendMsg(agv.getAgvId(), "目标机台:" + roadDao.getDevicegroup());

				// 因为是引用，此处不用save
				// iAgv.saveCache(agv);
				return true;
			} else {
				// 没有路线，数据上的错误 -1
				agvlog.error(String.format("%d 到 %d 没有路线？", dotno, gbean.getDotno()));
				return false;
			}
		}

	}

	/**
	 * 机台只上料
	 * 
	 * @param agv
	 * @param agvMount
	 * @param dot
	 * @param device
	 * @param deviceEvent
	 */
	void onlyIn(AgvBean agv, AgvMountBean agvMount, DotBean dot, DeviceBean device, IDeviceProtocol deviceEvent) {
		// 小车上层未操作+小车上面有料+设备上层传输
		if (device.isUpTrans() && agv.isUpHasTrans() == false && agvMount.isUpFull()) {
			// 小车上层发货
			MsgCore.sendMsg(agv.getAgvId(), "AGV已就位,等待机台回复");
			agv.setCurrentTrans(AgvCurrentTransEnum.UpOut);
			iAgv.saveCache(agv);

			// 需要对接设备上层收货
			byte[] cmd = deviceEvent.applyTransfer(device.getLine(), TransDirectionEnum.OnlyIn);
			sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请传输", cmd,
					device.getDeviceGroup());
			return;
		}
		// 小车下层未操作+小车下面有料+设备下层传输
		if (device.isDownTrans() && agv.isDownHasTrans() == false && agvMount.isDownFull()) {
			MsgCore.sendMsg(agv.getAgvId(), "AGV已就位,等待机台回复");
			agv.setCurrentTrans(AgvCurrentTransEnum.DownOut);
			iAgv.saveCache(agv);
			// 需要对接设备下层收货
			byte[] cmd = deviceEvent.applyTransfer(device.getLine(), TransDirectionEnum.OnlyIn);
			sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请传输", cmd,
					device.getDeviceGroup());
			return;
		}

		// 做传输完成

		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
		}
		byte[] goout = deviceEvent.applyLeave(device.getLine(), TransDirectionEnum.OnlyIn);
		sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请离开", goout,
				device.getDeviceGroup());

	}

	/**
	 * 机台只下料
	 * 
	 * @param agv
	 * @param agvMount
	 * @param dot
	 * @param device
	 * @param deviceEvent
	 */
	void onlyOut(AgvBean agv, AgvMountBean agvMount, DotBean dot, DeviceBean device, IDeviceProtocol deviceEvent) {
		// 小车上层未操作+小车上面非空+设备上层传输
		if (agv.isUpHasTrans() == false && device.isUpTrans() && agvMount.isUpFull() == false) {
			MsgCore.sendMsg(agv.getAgvId(), "AGV已就位,等待机台回复");
			// 小车上层收货
			agv.setCurrentTrans(AgvCurrentTransEnum.UpIn);
			iAgv.saveCache(agv);

			// 需要对接设备上层发货
			byte[] cmd = deviceEvent.applyTransfer(device.getLine(), TransDirectionEnum.OnlyOut);
			sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请传输", cmd,
					device.getDeviceGroup());

			agvlog.debug("小车上层收货，并向目标发送指令" + Tools.byte2HexStr(cmd));
			return;
		}
		// 小车下层未操作+小车下面非空 +设备下层传输
		if (agv.isDownHasTrans() == false && device.isDownTrans() && agvMount.isDownFull() == false) {
			MsgCore.sendMsg(agv.getAgvId(), "AGV已就位,等待机台回复");
			// 小车下层收货
			agv.setCurrentTrans(AgvCurrentTransEnum.DownIn);
			iAgv.saveCache(agv);

			// 需要对接设备下层发货
			byte[] cmd = deviceEvent.applyTransfer(device.getLine(), TransDirectionEnum.OnlyOut);
			sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请传输", cmd,
					device.getDeviceGroup());
			return;
		}

		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
		}
		byte[] goout = deviceEvent.applyLeave(device.getLine(), TransDirectionEnum.OnlyOut);
		sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请离开", goout,
				device.getDeviceGroup());

	}

	/**
	 * 同时上下料
	 * 
	 * @param agv
	 * @param agvMount
	 * @param dot
	 * @param device
	 * @param deviceEvent
	 */
	void InAndOut(AgvBean agv, AgvMountBean agvMount, DotBean dot, DeviceBean device, IDeviceProtocol deviceEvent) {
		if (agv.isDownHasTrans() == false && agv.isUpHasTrans() == false) {
			// 同时传输
			MsgCore.sendMsg(agv.getAgvId(), "AGV已就位,等待机台回复");
			if (agvMount.isUpFull()) {
				// 上面有料，上出下入
				agv.setCurrentTrans(AgvCurrentTransEnum.UpOutAndDownIn);
			} else {
				// 上面没料 上入下出
				agv.setCurrentTrans(AgvCurrentTransEnum.UpInAndDownOut);
			}
			iAgv.saveCache(agv);
			// 先通知对接设备收货
			byte[] cmd = deviceEvent.applyTransfer(device.getLine(), TransDirectionEnum.Both);
			sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请传输", cmd,
					device.getDeviceGroup());
			return;
		}

		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
		}
		byte[] goout = deviceEvent.applyLeave(device.getLine(), TransDirectionEnum.Both);
		sendTools.sendDeviceData(device.getIp(), device.getPort(), device.getLine(), "申请离开", goout,
				device.getDeviceGroup());
	}

}
